#pragma once
#include <string>
#include <variant>
#include <sstream>
#include <cstdlib>
#include <cwchar>
#include <Python.h>
using namespace std;

namespace GeneralMethod
{
	inline void to_upper(std::string& origin_data)
	{
		std::transform(origin_data.begin(), origin_data.end(), origin_data.begin(), ::toupper);
	};

	inline bool end_with(std::string a_string, std::string b_string) {
		int length = b_string.size();
		if (b_string.size() > a_string.size()) {
			return false;
		}
		if (a_string.find(b_string) == a_string.size() - length) {
			return true;
		}
		else {
			return false;
		}
	};

	template<typename T>
	void delete_items_by_index(std::vector<T>& origin_vec, std::vector<int> index_vec)
	{
		std::set<int> index_set(index_vec.begin(), index_vec.end());
		std::vector<int> index_vec_2(index_set.begin(), index_set.end());
		std::reverse(index_vec_2.begin(), index_vec_2.end());
		for (auto& i : index_vec_2)
		{
			origin_vec.erase(origin_vec.begin() + i);
		}
	};

	inline void strip(string& string1) {
		string1.erase(remove_if(string1.begin(), string1.end(), ::isspace), string1.end());
	};

	inline std::string strip_front_and_back(string& string1) {
		auto start = std::find_if_not(string1.begin(), string1.end(), [](unsigned char c) { return std::isspace(c); });
		auto end = std::find_if_not(string1.rbegin(), string1.rend(), [](unsigned char c) { return std::isspace(c); }).base();
		return (start >= end) ? std::string() : std::string(start, end);
	};

	inline bool is_contain_alpha_except_e(std::string& origin_data)
	{
		for (auto& i : origin_data)
		{
			if (std::isalpha(i) && i != 'e' && i != 'E')
			{
				return true;
			}
		}
		return false;
	}

	//在指定的dim2_list中寻找target
	//    =======>type_=1:dim2_list中只存在一个结果
	//    =======>type_=2:dim2_list存在多个结果，全找到并返回
	template<typename T>
	vector<vector<T>> search_items(T target, vector<vector<T>>& dim2_list, int index_location, int type_) {
		vector<vector<T>> result = {};
		if (type_ == 1) {
			for (auto& i : dim2_list) {
				if (i[index_location] == target) {
					result.push_back(i);
					return result;
				}
			}
			result.emplace_back();
			return result;
		}
		else {
			for (auto& i : dim2_list) {
				if (i[index_location] == target) {
					result.push_back(i);
				}
			}
			if (result.empty()) {
				result.emplace_back();
			}
			return result;
		}
	};

	template<typename T>
	vector<T> matrix_cross_multiply(vector<T> vector1, vector<T> vector2) {
		vector<T> result;
		auto& a_x = vector1[0];
		auto& a_y = vector1[1];
		auto& a_z = vector1[2];
		auto& b_x = vector2[0];
		auto& b_y = vector2[1];
		auto& b_z = vector2[2];
		result.push_back(a_y * b_z - b_y * a_z);
		result.push_back(a_z * b_x - b_z * a_x);
		result.push_back(a_x * b_y - b_x * a_y);
		return result;
	};

	template<typename T>
	vector<T> add_vector(vector<T> vector1, vector<T> vector2) {
		if (vector1.size() != vector2.size()) {
			throw;
		}
		vector<T> result;
		for (int i = 0; i < vector1.size(); ++i) {
			result.push_back(vector1[i] + vector2[i]);
		}
		return result;
	};

	template<typename T>
	vector<T> minus_vector(vector<T> vector1, vector<T> vector2) {
		if (vector1.size() != vector2.size()) {
			throw;
		}
		vector<T> result;
		for (int i = 0; i < vector1.size(); ++i) {
			result.push_back(vector1[i] + vector2[i]);
		}
		return result;
	};

	inline bool isVariantEmpty(std::variant<int, float, std::string>& origin_data)
	{
		if (!holds_alternative<std::string>(origin_data))
		{
			return false;
		}
		else
		{
			std::string temp = *get_if<std::string>(&origin_data);
			if (temp.empty())
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	};

	template <typename T>
	PyObject* change_vector_to_list(std::vector<T>& origin_data)
	{
		PyObject* res = PyList_New(origin_data.size());
		for (int i = 0; i < origin_data.size(); i++)
		{
			if constexpr (std::is_same_v<T, int>)
			{
				PyList_SET_ITEM(res, i, PyLong_FromLong(origin_data[i]));
			}
			else if constexpr (std::is_same_v<T, double>)
			{
				PyList_SET_ITEM(res, i, PyFloat_FromDouble(origin_data[i]));
			}
		}
		return res;
	}

	template <typename T>
	PyObject* change_map_to_dict(std::map<T, std::vector<int>>& origin_data)
	{
		PyObject* res = PyDict_New();
		for (auto& i : origin_data)
		{
			PyObject* key;
			PyObject* value;
			if constexpr (std::is_same_v<T, std::string>)
			{
				key = PyUnicode_FromString(i.first.c_str());
			}
			else if constexpr (std::is_same_v<T, int>)
			{
				key = PyLong_FromLong(i.first);
			}
			value = change_vector_to_list(i.second);
			PyDict_SetItem(res, key, value);
		}
		return res;
	};

	inline void replaceSplash(std::string& str)
	{
		for (size_t i = 0; i < str.size(); ++i)
		{
			if (str.at(i) == '\\')
			{
				str[i] = '/';
			}
		}
	};

	static void Trim(std::string& value)
	{
		if (!value.empty())
		{
			value.erase(0, value.find_first_not_of(" "));
			value.erase(value.find_last_not_of(" ") + 1);
		}
		if (!value.empty())
		{
			value.erase(0, value.find_first_not_of("\""));
			value.erase(value.find_last_not_of("\"") + 1);
		}
	};

	inline void split(std::vector<std::string>& result, const std::string& line, const char* sep)
	{
		result.clear();
		const size_t sizeLine = line.size();
		const char* str = line.c_str();
		int start = 0;
		int end = 0;

		for (int i = 0; i < sizeLine; i++)
		{
			if (str[i] == sep[0])
			{
				std::string lineValue(str + start, end);
				Trim(lineValue);
				if (!lineValue.empty())
				{
					result.push_back(lineValue);
				}
				else {
					result.push_back("");
				}
				start = i + 1;
				end = 0;
			}
			else
			{
				end++;
			}
		}
		if (end > 0)
		{
			std::string lineValue(str + start, end);
			Trim(lineValue);
			if (!lineValue.empty())
			{
				result.push_back(lineValue);
			}
		}
	};
	
	inline std::string GetName(const std::string& value)
	{
		std::string result;
		size_t pos = value.find("=");

		if (pos != std::string::npos)
		{
			result = value.substr(pos + 1);
			if (result.find(":") != string::npos)
			{
				std::replace(result.begin(), result.end(), ':', '_');
			}
			Trim(result);
			return result;
		}
		else
		{
			result = value;
			if (result.find(":") != string::npos)
			{
				std::replace(result.begin(), result.end(), ':', '_');
			}
			return result;
		}
	};

	inline std::string GetLabel(const std::string& value)
	{
		size_t pos = value.find("=");
		if (pos != std::string::npos)
		{
			std::string result;
			result = value.substr(0, pos);
			Trim(result);
			std::transform(result.begin(), result.end(), result.begin(), ::toupper);
			return result;
		}
		else
		{
			std::string result;
			result.resize(value.size());
			std::transform(value.begin(), value.end(), result.begin(), ::toupper);
			Trim(result);
			return result;
		}
	}

	inline bool isNum(std::string s)
	{
		std::stringstream sin(s);
		double t;
		char p;
		if (!(sin >> t))
		{
			return false;
		}
		if (sin >> p)
		{
			return false;
		}
		return true;
	};

	template<typename T>
	bool has_member(vector<T>& vector1, T target) 
	{
		if (std::find(vector1.begin(), vector1.end(),target) == vector1.end())
		{
			return false;
		}
		return true;
	};

	inline wchar_t* char_to_wchar(const char* str) {
		size_t len = mbstowcs(nullptr, str, 0) + 1; // 计算所需缓冲区大小
		wchar_t* wstr = new wchar_t[len];
		mbstowcs(wstr, str, len);
		return wstr;
	};

};
